package com.briup.auth.service;

import com.briup.auth.constant.AuthConstant;
import com.briup.common.cache.CacheService;
import com.briup.common.exception.CustomerException;
import com.briup.common.jwt.JwtUtil;
import com.briup.common.sms.PhoneUtil;
import com.briup.common.sms.RandomUtil;
import com.briup.common.web.MessageStatus;
import com.briup.user.entity.Role;
import com.briup.user.entity.User;
import com.briup.user.entity.extend.UserEx;
import com.briup.user.mapper.UserMapper;
import com.briup.user.mapper.extend.UserExtendMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description 认证相关的业务操作
 * @Author wood
 */
@Service
public class UserAuthService {

    @Autowired
    private UserExtendMapper userExtendMapper;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CacheService cacheService;

    /**
     * 通过电话查询用户信息
     */
    public User findByTelephone(String telephone){

        if(!PhoneUtil.verifyPhoneNum(telephone)){
            throw new CustomerException(MessageStatus.PARAM_TELEPHONE_FORMAT_ERROR);
        }
        return userExtendMapper.findByTelephone(telephone);
    }

    /**
     * 根据电话自动创建一个默认新用户
     */
    private User insertDefaultUserWithTelephone(String telephone){
        if(!PhoneUtil.verifyPhoneNum(telephone)){
            throw new CustomerException(MessageStatus.PARAM_TELEPHONE_FORMAT_ERROR);
        }

        UserEx user = new UserEx();
        user.setUsername("briup-"+ RandomUtil.getRandomStr(10));
        user.setPassword(RandomUtil.getRandomStr(8));
        user.setTelephone(telephone);

        //默认用户 固定的角色就是ROLE_USER
        Role role = new Role();
        role.setId(1);
        role.setName("ROLE_USER");

        user.setRoles(Arrays.asList(role));
        userMapper.insert(user);

        userExtendMapper.insertUserAndRole_r(user.getId(),user.getRoles().get(0).getId());

        return user;
    }

    /**
     * 账户名/密码 登录
     */
    public String loginWithUsernameAndPassword(String username,String password){

        User user = userExtendMapper.findByUserName(username);
        // 用户不存在 或 密码错误 ，都是返回 USER_LOGIN_ERROR 错误信息
        if(user == null || !user.getPassword().equals(password)){
            throw new CustomerException(MessageStatus.USER_LOGIN_ERROR);
        }

        return getTokenFromUser(user);
    }

    /**
     * 手机号/验证码 登录
     */
    @Transactional
    public String loginWithTelephoneAndVerifyCode(String telephone, String verifyCode) {
        if("briup".equals(verifyCode)){
            return mockLogin();
        }

        // 验证手机验证码是否正确
        if(!PhoneUtil.verifyPhoneNum(telephone)){
            throw new CustomerException(MessageStatus.PARAM_TELEPHONE_FORMAT_ERROR);
        }

        // 校验验证码是否正确
        if(cacheService.get(telephone) == null){
            throw new CustomerException(MessageStatus.PARAM_VERIFY_CODE_NOT_EXIST);
        }
        String obj = cacheService.get(telephone);
        if(!obj.equals(verifyCode)){
            throw new CustomerException(MessageStatus.PARAM_VERIFY_CODE_NOT_MATCH);
        }


        //通过手机号查找用户
        User user =  userExtendMapper.findByTelephone(telephone);

        //该用户不存在，那么就自动注册一个默认用户
        if(user == null){
            user = this.insertDefaultUserWithTelephone(telephone);
        }

        return getTokenFromUser(user);
    }

    private String mockLogin(){
        //通过手机号查找用户
        //1	tom	张三丰	123	 13812811111
        User user =  userExtendMapper.findByTelephone("13812811111");
        return getTokenFromUser(user);
    }

    /**
     * 通过user对象获取token
     * 并将电话对应的验证码从redis中删除掉
     * 并将生成的用户token保存到redis中
     */
    private String getTokenFromUser(User user){

        Map<String,Object> map = new HashMap<>();
        map.put("id",this.replaceNull(user.getId()));
        map.put("username",this.replaceNull(user.getUsername()));
        map.put("realname",this.replaceNull(user.getRealName()));
        map.put("telephone",this.replaceNull(user.getTelephone()));
        if(user instanceof UserEx){
            UserEx userEx = (UserEx) user;
            map.put("role",userEx.getRoles());
        }
        String token = JwtUtil.sign(String.valueOf(user.getId()),map);

        String key = getKeyOfTokenInRedisWithIdAndUsername(String.valueOf(user.getId()),user.getUsername());
        // 将此用户对应的token存放到redis中
        cacheService.setEx(key,token,JwtUtil.EXPIRE_TIME_MINUTE, TimeUnit.SECONDS);

        // 删除此手机号对应的验证码
        cacheService.delete(user.getTelephone());

        return token;
    }

    /**
     * 如果是null的话，替换为""，否则jwt签发token会报错
     */
    private String replaceNull(Object obj) {
        return obj == null ? "" : obj.toString();
    }

    /**
     * 通过用户id和用户名，获取用户token在redis存储的key的名称
     */
    private String getKeyOfTokenInRedisWithIdAndUsername(String userId,String username){
        return AuthConstant.KEY_TOKEN_PREFIX_REDIS+userId+"_"+username;
    }

    /**
     * 通过token，获取用户token在redis存储的key的名称
     */
    private String getKeyOfTokenInRedisWithToken(String token){
        String userId = JwtUtil.getUserId(token);
        String username = (String) JwtUtil.getInfo(token).get("username");
        return getKeyOfTokenInRedisWithIdAndUsername(userId,username);
    }

    /**
     * 通过token获取用户信息
     */
    public User getUserFromToken(String token){


        String userId;

        if("briup".equals(token)){
            userId = "1";
        }else{
            userId = JwtUtil.getUserId(token);
        }

        User user = userMapper.selectByPrimaryKey(Integer.valueOf(userId));

        if(user == null){
            throw new CustomerException(MessageStatus.USER_TOKEN_INVALID);
        }

        user.setPassword(null);

        return user;
    }

    /**
     * 验证token是否有效
     */
    public boolean checkToken(String jwtToken) {
        boolean result = false;
        // 验证 token
        try {
            JwtUtil.checkSign(jwtToken);
            String key = getKeyOfTokenInRedisWithToken(jwtToken);
            result = cacheService.exists(key);
        } catch (Exception e) {
            // noop
        }

        return result;
    }

    /**
     * 用户退出
     */
    public void logout(String jwtToken) {
        try {
            String key = getKeyOfTokenInRedisWithToken(jwtToken);
            if(cacheService.exists(key)){
                cacheService.delete(key);
            }
            else{
                throw new CustomerException(MessageStatus.USER_TOKEN_INVALID);
            }
        } catch (Exception e) {
            throw new CustomerException(MessageStatus.USER_TOKEN_INVALID);
        }
    }


}
